home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The 640 MEG Shareware Studio 2
/
The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO
/
clang
/
nn.zip
/
ADMIN.C
< prev
next >
Wrap
C/C++ Source or Header
|
1989-12-31
|
21KB
|
1,002 lines
/*
* nnadmin - nn administator program
*/
#include <signal.h>
#include <errno.h>
#include "config.h"
#include "db.h"
#include "term.h"
static char *pre_input;
static int verbose = 1;
extern int group_completion();
static get_cmd(prompt1, prompt2)
char *prompt1, *prompt2;
{
char c;
if (s_hangup) {
printf("\nnnmaster hangup\n");
nn_exit(0);
}
if (pre_input) {
if ((c = *pre_input++) == NUL)
nn_exit(0);
} else {
if (prompt1) printf("\r%s\n", prompt1);
if (prompt2) printf("\r%s >>>", prompt2);
fl;
raw();
c = get_c();
unset_raw();
if (c == K_interrupt)
s_keyboard++;
else
printf("%c\n\n\r", c);
}
if (islower(c))
c = toupper(c);
return c;
}
static long get_entry(prompt_str, min_val, max_val)
char *prompt_str;
long min_val, max_val;
{
char buf[100];
long val;
loop:
printf("%s %ld..%ld (or all): ", prompt_str, min_val, max_val);
fl;
gets(buf);
if (buf[0] == 'a' || buf[0] == NUL)
return -1L;
val = atol(buf);
if (val < min_val || val > max_val) goto loop;
return val;
}
static admin_confirm(action)
char *action;
{
char buffer[100];
if (pre_input) return 1;
sprintf(buffer, "Confirm %s Y)es N)o", action);
return get_cmd((char *)NULL, buffer) == 'Y';
}
char *get_groupname()
{
char * groupname;
raw();
printf("Group: ");
fl;
groupname = get_s(NONE, NONE, NONE, group_completion);
unset_raw();
putchar(NL); putchar(CR);
if (groupname == NULL) return NULL;
if (groupname[0]) return groupname;
if (current_group == NULL) return NULL;
if (current_group->group_flag & G_FOLDER) return NULL;
return current_group->group_name;
}
admin_mode(input_string)
char *input_string;
{
int was_raw = unset_raw();
if (input_string && *input_string) {
pre_input = input_string;
} else {
pre_input = NULL;
printf("\nMaster is%s running\n",
access(relative(lib_directory, "MPID"), 0) ? " NOT" : "");
}
for (;;) {
switch(get_cmd(
"\nC)onf E)xpire G)roups I)nit L)og M)aster Q)uit S)tat U)pdate V)alidate W)akeup",
"ADMIN")) {
case 'M':
master_admin();
break;
case 'W':
kill_master_1(SIGALRM);
break;
case 'E':
if (admin_confirm("Expire All Groups"))
send_master('X', -1L, 0L);
break;
case 'I':
if (admin_confirm("INITIALIZATION, i.e. recollect all groups"))
send_master('R', -1L, 0L);
break;
case 'G':
group_admin();
break;
case 'L':
log_admin();
break;
case 'S':
master_status();
break;
case 'C':
show_config();
break;
case 'U':
update_master();
break;
case 'Z':
verbose = 0;
/* FALL THRU */
case 'V':
validate_groups();
verbose = 1;
break;
case '=':
verbose = !verbose;
break;
case 'Q':
if (was_raw) raw();
return;
}
}
}
static update_master()
{
extern FILE *master_file;
register group_header *gh;
int ngp;
ngp = master.number_of_groups;
rewind(master_file);
db_read_master(master_file, &master);
if (master.number_of_groups != ngp) {
printf("\nNumber of groups changed from %d to %d\n",
ngp, master.number_of_groups);
printf("You must restart nnadmin to access the new group(s)\n");
ngp = master.number_of_groups;
}
ngp = 0;
Loop_Groups_Header(gh)
if (update_group(gh) < 0) ngp++;
if (ngp) printf("There are %d blocked groups\n", ngp);
}
static master_admin()
{
register char c;
int cur_group;
long value;
register group_header *gh;
for (;;) {
switch (c = get_cmd(
"\nA)ll E)mpty F)iles G)roup K)ill N)on-empty O)ptions S)tat T)race",
"MASTER")) {
case 'G':
cur_group = (int)get_entry("Group number",
0L, (long)(master.number_of_groups - 1));
if (cur_group >= 0)
dump_m_entry(&active_groups[cur_group]);
break;
case 'A':
case 'E':
case 'N':
cur_group = -1;
s_keyboard = 0;
while (++cur_group < master.number_of_groups) {
if (s_keyboard || s_hangup) break;
gh = &active_groups[cur_group];
if (c == 'N' && gh->last_l_article == 0) continue;
if (c == 'E' && gh->last_l_article != 0) continue;
dump_m_entry(gh);
}
break;
case 'F':
find_files(-1);
break;
case 'O':
c = get_cmd("r)epeat_delay e)xpire_level", "OPTION");
if (c != 'R' && c != 'E') break;
value = get_entry("Option value", 1L, 10000L);
if (value < 0) break;
send_master(tolower(c), value, 0L);
break;
case 'S':
master_status();
break;
case 'T':
send_master('T', 0L, 0L);
break;
case 'K':
if (admin_confirm("Stop nn Master"))
kill_master_1(SIGHUP);
break;
default:
return;
}
}
}
static log_admin()
{
char command[FILENAME + 100], c;
if (pre_input && *pre_input == NUL) {
c = SP;
goto log_tail;
}
loop:
c = get_cmd(
"\n(1-9)tail A)dmin C)ollect E)rrors G)roup R)eports e(X)pire (*)all (@)clean",
"LOG");
if (c < SP || c == 'Q') return;
if (c == '@') {
if (admin_confirm("Truncation")) {
sprintf(command,
"cd %s && mv Log Log.old && ./log_entry A Truncated && chmod 666 Log",
lib_directory);
system(command);
}
return;
}
if (c == 'G') {
char *groupname;
groupname = get_groupname();
sprintf(command, "grep '%s' %s/Log | %s",
groupname, lib_directory, pager);
system(command);
goto loop;
}
log_tail:
if (c == '$' || c == SP || isdigit(c)) {
int n;
n = isdigit(c) ? 10 * (c - '0') : 10;
sprintf(command, "tail -%d %s/Log", n, lib_directory);
system(command);
goto loop;
}
if (c == '*') {
c = '.';
}
sprintf(command, "grep '^%c:' %s/Log | %s", c, lib_directory, pager);
system(command);
goto loop;
}
static group_admin()
{
char *groupname;
register group_header *gh;
new_group:
groupname = get_groupname();
gh = lookup(groupname);
if (gh == NULL) {
printf("No group named %s\n", groupname);
goto new_group;
}
for (;;) {
switch (get_cmd(
"\nC)lear_flag D)ata E)xpire F)iles G)roup H)eader S)et_flag R)ecollect",
"GROUP")) {
case 'D':
dump_group(gh, 0);
break;
case 'H':
dump_m_entry(gh);
break;
case 'F':
find_files(gh->group_num);
break;
case 'S':
flag_admin(gh, "Set", 1);
break;
case 'C':
flag_admin(gh, "Clear", 0);
break;
case 'R':
if (admin_confirm("Recolletion of Group"))
send_master('R', (long)gh->group_num, 0L);
break;
case 'E':
if (admin_confirm("Expire Group"))
send_master('X', (long)gh->group_num, 0L);
break;
case 'G':
goto new_group;
default:
return;
}
}
}
static flag_admin(gh, mode_str, set_flag)
group_header *gh;
char *mode_str;
int set_flag;
{
char buffer[50];
int new_flag = 0;
putchar(NL);
dump_g_flag(gh);
sprintf(buffer, "%s FLAG", mode_str);
switch (get_cmd(
"\nA)lways_digest N)ever_digest M)oderated C)ontrol no_(D)ir",
buffer)) {
default:
return;
case 'M':
new_flag = G_MODERATED;
break;
case 'C':
new_flag = G_CONTROL;
break;
case 'D':
new_flag = G_NO_DIRECTORY;
break;
case 'A':
new_flag = G_ALWAYS_DIGEST;
break;
case 'N':
new_flag = G_NEVER_DIGEST;
break;
}
if (new_flag & (G_CONTROL | G_NO_DIRECTORY))
if (!admin_confirm("Flag Change"))
new_flag = 0;
if (new_flag) {
if (set_flag) {
if (gh->group_flag & new_flag)
new_flag = 0;
else {
send_master('S', (long)gh->group_num, (long)new_flag);
gh->group_flag |= new_flag;
}
} else {
if ((gh->group_flag & new_flag) == 0)
new_flag = 0;
else {
send_master('C', (long)gh->group_num, (long)new_flag);
gh->group_flag &= ~new_flag;
}
}
}
if (new_flag == 0)
printf("NO CHANGE\n");
else
dump_g_flag(gh);
}
static find_files(group)
group_number group;
{
char command[512];
if (group < 0)
sprintf(command, "ls -l %s/DATA | %s", db_directory, pager);
else
sprintf(command, "ls -l %s/DATA/%d.*", db_directory, group);
system(command);
}
static master_status()
{
int cur_group;
long articles, disk_use;
register group_header *gh;
printf("\nMaster:\n");
printf(" last_scan: %s\n", date_time(master.last_scan));
printf(" no of groups: %d\n", master.number_of_groups);
printf(" next write: %ld\n", master.next_group_write_offset);
articles = disk_use = 0;
for (cur_group = 0; cur_group < master.number_of_groups; cur_group++) {
gh = &active_groups[cur_group];
#define DISK_BLOCKS(bytes) (((bytes) + 1023) / 1024)
disk_use += DISK_BLOCKS(gh->index_write_offset);
disk_use += DISK_BLOCKS(gh->data_write_offset);
articles += gh->last_l_article - gh->first_l_article + 1;
}
printf("\n Articles: %ld\n", articles);
printf( " Disk usage: %ld k\n", disk_use);
}
static show_config()
{
extern char news_active[], news_directory[];
#ifdef NNTP
extern char nntp_server[];
#endif
printf("\nConfiguration:\n\n");
printf("BIN: %s\nLIB: %s\nDB: %s\nNEWS: %s\n",
BIN_DIRECTORY,
lib_directory,
db_directory,
news_directory);
printf("ACTIVE: %s\n", news_active);
#ifdef NNTP
if (use_nntp)
printf("NNTP ACTIVE. server=%s\n", nntp_server);
else
printf("NNTP NOT ACTIVE\n");
#endif
#ifdef NETWORK_DATABASE
printf("Database is machine independent (network format).\n");
#ifdef NETWORK_BYTE_ORDER
printf("Local system assumes to use network byte order\n");
#endif
#else
printf("Database format is machine dependent (byte order and alignment)\n");
#endif
#ifdef STATISTICS
printf("Recording usage statistics\n");
#else
printf("No usage statistics are recorded\n");
#endif
printf("Default pager: %s\n", PAGER);
printf("Default printer: %s\n", PRINTER);
printf("Mail delivery program: %s\n", REC_MAIL);
#ifdef APPEND_SIGNATURE
printf("Query for appending .signature ENABLED\n");
#else
printf("Query for appending .signature DISABLED\n");
#endif
printf("Max pathname length is %d bytes\n", FILENAME-1);
}
static dump_m_entry(gh)
register group_header *gh;
{
update_group(gh);
printf("\n%s\t%d\n", gh->group_name, gh->group_num);
printf("first/last art: %06ld %06d\n",
gh->first_l_article, gh->last_l_article);
printf(" active info: %06ld %06d\n",
gh->first_article, gh->last_article);
printf("Offsets: index->%ld, data->%ld\n",
gh->index_write_offset,
gh->data_write_offset);
if (gh->group_flag)
dump_g_flag(gh);
}
static dump_g_flag(gh)
register group_header *gh;
{
printf("Flags: ");
if (gh->group_flag & G_BLOCKED) printf(" BLOCKED");
if (gh->group_flag & G_EXPIRE) printf(" EXPIRE");
if (gh->group_flag & G_MODERATED) printf(" MODERATED");
if (gh->group_flag & G_CONTROL) printf(" CONTROL");
if (gh->group_flag & G_NO_DIRECTORY) printf(" NO_DIRECTORY");
if (gh->group_flag & G_ALWAYS_DIGEST) printf(" ALWAYS_DIGEST");
if (gh->group_flag & G_NEVER_DIGEST) printf(" NEVER_DIGEST");
printf("\n");
}
static dump_group(gh, validate)
group_header *gh;
int validate;
{
FILE *data, *ix;
data_header hdr;
off_t data_offset, real_offset, next_offset;
cross_post_number cross_post;
article_number first_article, next_article, this_art;
int n, was_digest;
char buffer[512];
if (!validate) {
if (init_group(gh) <= 0)
printf("cannot access group %s\n", gh->group_name);
update_group(gh);
}
if (validate)
first_article = gh->first_l_article;
else
first_article = get_entry("First article",
(long)gh->first_l_article,
(long)gh->last_l_article);
if (first_article < 0) first_article = gh->first_l_article;
if (first_article <= 0) first_article = 1;
ix = open_data_file(gh, 'x', OPEN_READ);
if (ix == NULL) {
if (verbose) printf("NO INDEX FILE\n");
return 0;
}
next_offset = get_index_offset(gh, first_article);
fseek(ix, next_offset, 0);
if (!db_read_offset(ix, &real_offset)) {
if (verbose) printf("NO INDEX FOR ARTICLE %ld\n", (long)first_article);
fclose(ix);
return 0;
}
data_offset = real_offset;
fseek(ix, next_offset, 0);
data = open_data_file(gh, 'd', OPEN_READ);
if (data == NULL) {
if (verbose) printf("NO DATA FILE\n");
fclose(ix);
return 0;
}
next_article = first_article;
s_keyboard = 0;
was_digest = 0;
if (!validate) {
clrdisp();
pg_init(1, 1);
}
while (next_article <= gh->last_l_article) {
if (s_hangup || s_keyboard) goto out;
if (!db_read_offset(ix, &real_offset)) {
if (verbose)
printf("NO INDEX FOR ARTICLE %ld\n", (long)next_article);
goto err;
}
if (data_offset != real_offset)
goto ix_data_err;
fseek(data, data_offset, 0);
in_digest:
if (!validate && pg_scroll(6)) {
s_keyboard = 1;
goto out;
}
next_offset = data_offset;
if (!db_read_art(data, &hdr, &data_offset)) {
if (real_offset == gh->data_write_offset || was_digest)
break;
if (verbose) printf("No article header for article # %ld\n",
(long)next_article);
goto err;
}
if (hdr.dh_number) {
if (was_digest) {
next_article++;
if (!db_read_offset(ix, &real_offset))
goto ix_eof_err;
if (real_offset != next_offset)
goto ix_data_err;
}
this_art = hdr.dh_number < 0 ? -hdr.dh_number : hdr.dh_number;
if (this_art != next_article) {
if (this_art < next_article) {
if (verbose)
printf("Article # %ld out of sequence\n",
(long)this_art);
goto err;
}
/*
if (this_art == (next_article + 1))
printf("Article # %ld missing (OK)\n",
(long)next_article);
else
printf("Articles # %ld -> %ld missing (OK)\n",
(long)next_article, (long)this_art);
*/
while (this_art > next_article) {
if (!db_read_offset(ix, &next_offset))
goto ix_eof_err;
if (next_offset != real_offset)
goto ix_data_err;
next_article++;
}
}
}
if (!validate)
printf("\noffset = %ld, article # = %ld\n",
(long)real_offset, (long)(hdr.dh_number));
if (hdr.dh_lpos == (off_t)0) { /* article not accessible */
if (verbose)
printf("# %ld: NO ARTICLE (ok)\n", (long)next_article);
continue;
}
data_offset += hdr.dh_cross_postings * sizeof(cross_post_number)
+ hdr.dh_sender_length
+ hdr.dh_subject_length;
if (hdr.dh_cross_postings) {
if (!validate)
printf("xpost(%d):", hdr.dh_cross_postings);
n = hdr.dh_cross_postings;
while (--n >= 0) {
if (fread((char *)&cross_post, sizeof(cross_post_number), 1, data)!= 1)
goto data_error;
#ifdef NETWORK_DATABASE
#ifndef NETWORK_BYTE_ORDER
cross_post = ntohl(cross_post);
#endif
#endif
if (validate) {
if (cross_post >= master.number_of_groups) {
if (verbose)
printf("xpost group out of range: %ld (article # %ld)\n",
(long)cross_post, (long)next_article);
goto err;
}
} else
printf(" %d", cross_post);
}
if (!validate) printf("\n");
}
if (!validate)
if (IS_DIGEST_HEADER(hdr))
printf("digest header ");
else
if (IS_SUB_DIGEST(hdr))
printf("digest article ");
else
printf("normal article ");
if (!validate)
printf("ts=%lu hp=%ld, fp=+%d, lp=%ld, rep=%d, lines=%d\n",
(long unsigned)hdr.dh_date,
(long)hdr.dh_hpos, (int)hdr.dh_fpos, (long)hdr.dh_lpos,
hdr.dh_replies, hdr.dh_lines);
if (hdr.dh_sender_length) {
if (fread(buffer, sizeof(char), (int)hdr.dh_sender_length, data)
!= hdr.dh_sender_length) goto data_error;
buffer[hdr.dh_sender_length] = NUL;
if (!validate)
printf("Sender(%d): %s\n", hdr.dh_sender_length, buffer);
} else
if (!validate)
printf("No sender\n");
if (hdr.dh_subject_length) {
if (fread(buffer, sizeof(char), (int)hdr.dh_subject_length, data)
!= hdr.dh_subject_length) goto data_error;
buffer[hdr.dh_subject_length] = NUL;
if (!validate)
printf("Subj(%d): %s\n", hdr.dh_subject_length, buffer);
} else
if (!validate)
printf("No subject\n");
if (IS_DIGEST_HEADER(hdr) || IS_SUB_DIGEST(hdr)) {
was_digest = 1;
goto in_digest;
}
was_digest = 0;
next_article++;
}
out:
if (s_keyboard == 0 && data_offset != gh->data_write_offset) {
if (verbose)
printf("\n*** ERROR: Next data offset %ld wrong. real offset=%ld\n",
gh->data_write_offset, data_offset);
goto err;
}
fclose(data);
fclose(ix);
return 1;
data_error:
if (verbose) printf("\n*** END OF FILE on DATA FILE\n\n");
goto err;
ix_eof_err:
if (verbose) printf("NO INDEX FOR ARTICLE %ld\n", (long)next_article);
goto err;
ix_data_err:
if (verbose) {
printf("\n*** OFFSET ERROR in article # %ld offsets:\n",
(long)next_article);
printf(" Calcuated offset %ld differs from index %ld\n",
(long)data_offset, (long)real_offset);
}
goto err;
err:
fclose(data);
fclose(ix);
return 0;
}
send_master(command, arg1, arg2)
char command;
long arg1, arg2;
{
FILE *gate;
gate = open_file(relative(lib_directory, "GATE"), OPEN_APPEND);
if (gate == NULL) {
printf("Cannot send to master\n");
return;
}
fprintf(gate, "%c;%ld;%ld;%s %s;\n",
command, arg1, arg2, user_name(), date_time((time_t)0));
fclose(gate);
log_entry('A', "SEND %c %ld %ld", command, arg1, arg2);
}
/* fake this for visit_active_file() */
/*ARGSUSED*/
group_header *add_new_group(name)
char *name;
{
return NULL;
}
/*
* make consistency check on all groups
*/
static file_error(gh, d_or_x, write_offset)
group_header *gh;
char d_or_x;
off_t write_offset;
{
FILE *f;
f = open_data_file(gh, d_or_x, OPEN_READ);
if (f == NULL) {
if (verbose)
printf("FILE '%c' NOT FOUND\n", d_or_x);
} else {
fseek(f, (off_t)0, 2);
if (ftell(f) >= write_offset) {
fclose(f);
return 0;
}
if (verbose)
printf("FILE '%c' IS SHORTER THAN NEXT WRITE OFFSET\n", d_or_x);
fclose(f);
}
return 1;
}
validate_groups()
{
register group_header *gh;
group_number num;
import char *pname;
if (strcmp(pname, "nnadmin")) {
printf("You can only run VALIDATION from nnadmin\n");
return;
}
s_keyboard = 0;
Loop_Groups_Number(num) {
if (s_hangup || s_keyboard) break;
gh = &active_groups[num];
if (init_group(gh) <= 0) continue; /* no directory */
if (verbose) { printf("\r%s: ", gh->group_name); clrline(); }
update_group(gh);
if (gh->group_flag & G_BLOCKED) {
if (verbose) printf("BLOCKED\n");
continue;
}
/*
* Check for major inconcistencies.
* Sometimes, news expire will reset article numbers
* to start from 0 again
*/
if (gh->last_l_article == 0) {
continue;
}
if (gh->first_article > (gh->last_l_article + 1) ||
gh->last_l_article > gh->last_article ||
gh->first_l_article > gh->first_article) {
if (verbose)
printf("RENUMBERING OF ARTICLES (active=%ld..%ld master=%ld..%ld)",
gh->first_article, gh->last_article,
gh->first_l_article, gh->last_l_article);
goto ask_collect;
}
/*
* Check existence and sizes of data files
*/
if (file_error(gh, 'x', gh->index_write_offset))
goto ask_collect;
if (file_error(gh, 'd', gh->data_write_offset))
goto ask_collect;
if (!dump_group(gh, 1))
goto ask_collect;
if (!verbose) continue;
if (gh->first_article > gh->first_l_article)
printf("unexpired articles: %ld\n",
(long)(gh->first_article - gh->first_l_article));
else
printf("OK\r");
continue;
ask_collect:
log_entry('V', "Database inconsistency in group %s", gh->group_name);
if (admin_confirm("\nRepair group"))
send_master('R', (long)gh->group_num, 0L);
}
}
kill_master_1(sig)
int sig;
{
if (kill_master(sig)) {
if (verbose) printf("sent signal %d to master\n", sig);
} else
if (errno == ESRCH) {
if (verbose) printf("master is not running\n");
} else
printf("cannot signal master (errno=%d)\n", errno);
}